#include <cubefs/api/tools/library.hpp>
#include <cubefs/api/exceptions.hpp>

#include <dlfcn.h>
#include <iostream>

#define CUBEFS_SOURCE "api-impl/posix/library.cpp:" CUBEFS_AT

namespace cubefs{ namespace api {

using namespace std;


SharedLibrary::SharedLibrary(): handle_(NULL), global_scope_(false), name_(NULL) {}

SharedLibrary::SharedLibrary(const SharedLibrary& copy): handle_(copy.handle_), global_scope_(copy.global_scope_), name_(NULL) {
	if (copy.name_ != NULL) {
		name_ = new String(*copy.name_);
	}
}

SharedLibrary::~SharedLibrary() throw ()
{
	if (handle_ != NULL) {
		dlclose(handle_);
	}

	if (name_ != NULL) {
		delete name_;
	}
}

void SharedLibrary::Setup(StringRef name, bool global_scope)
{
	if (name_ != NULL) {
		delete name_;
	}
	name_ = new String(name);
	global_scope_ = global_scope;

//	cout<<"configure Shared library: "<<name_->c_str()<<" "<<this<<endl;
}

void SharedLibrary::Open() {
	//cout<<"Open "<<name_->c_str()<<" "<<this<<endl;
	if ((handle_ = dlopen(name_->c_str(), (global_scope_ ?  RTLD_GLOBAL : RTLD_LOCAL) | RTLD_NOW)) == NULL) {
		throw CubefsException(CUBEFS_SOURCE, dlerror());
	}
}

void SharedLibrary::Close() {
	if (handle_ != NULL) {
		if (dlclose(handle_)) {
			throw CubefsException(CUBEFS_SOURCE, dlerror());
		}
		handle_ = NULL;
	}
}

void* SharedLibrary::GetHandle() const {
	return handle_;
}

void* SharedLibrary::GetSymbolAddress(StringRef symbol_name) const {
	if (handle_ != NULL)
	{
		void* ptr = NULL;
		if ((ptr = dlsym(handle_, symbol_name.c_str())) == NULL)
		{
			throw CubefsException(CUBEFS_SOURCE, dlerror());
		}
		return ptr;
	}
	else {
		throw CubefsException(CUBEFS_SOURCE, "The library " + (*name_) + "has not been loaded.");
	}
}


}}

#undef CUBEFS_SOURCE
